package com.wanwu.channel.notify.controller;

import com.wanwu.channel.common.enums.AlarmTypeEnum;
import com.wanwu.channel.common.enums.BusinessCodeEnum;
import com.wanwu.channel.common.enums.ExceptionEnum;
import com.wanwu.channel.common.exception.SystemException;
import com.wanwu.channel.common.util.DingUtil;
import com.wanwu.channel.common.util.LogUtil;
import com.wanwu.channel.common.util.SybUtil;
import com.wanwu.channel.core.util.apollo.ApolloMerchantUtil;
import com.wanwu.channel.dao.entity.ChannelMerchantInfoEntity;
import com.wanwu.channel.core.tool.AlarmPoolUtil;
import com.wanwu.channel.notify.config.TlConfig;
import com.wanwu.channel.notify.process.TongLianNotifyProcess;
import com.wanwu.monitor.api.enums.SystemEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.TreeMap;

/**
 * @ClassName TongLianNotifyController
 * @Description 接收通联支付回调处理
 * @Author husheng
 * @Date 2020-01-17 15:22
 */
@RestController
@RequestMapping("/tl")
public class TongLianNotifyController {

    private static Logger logger = LoggerFactory.getLogger(TongLianNotifyController.class);

    @Resource
    private TlConfig tlConfig;

    @Resource
    private AlarmPoolUtil alarmPoolUtil;

    @Resource
    private TongLianNotifyProcess tongLianNotifyProcess;

    @Resource
    private ApolloMerchantUtil apolloMerchantUtil;

    /**
     * 通联支付回调处理
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "/pay/notify", method = RequestMethod.POST)
    public void appPayNotify(HttpServletRequest request, HttpServletResponse response) {
        //动态遍历获取所有收到的参数,此步非常关键,因为收银宝以后可能会加字段,动态获取可以兼容
        TreeMap<String, String> params = getParams(request);
        LogUtil.info(logger, "收到通联支付回调通知，参数：{0}", params);
        try {
            //通知传输的编码为GBK
            request.setCharacterEncoding("gbk");
            response.setCharacterEncoding("gbk");
            // 接受到推送通知,首先验签
            boolean isSign = SybUtil.validSign(params, tlConfig.getAppKey());
            if (!isSign) {
                throw new SystemException(ExceptionEnum.TL1004);
            }
            //验签通过进行业务处理
            //bizCode用于从库里查询时的参数,线上已有业务全为万里目,且会调到这个回调方法的都是已有数据,故这里全部配置为wanlimu_code
            tongLianNotifyProcess.tongLianNotify(params, BusinessCodeEnum.WANLIMU.getBizCode(), tlConfig.getDingKey(), 0);
            //返回处理成功
            response.getOutputStream().write("success".getBytes());
            response.flushBuffer();
        } catch (Exception e) {
            LogUtil.error(logger, e, "通联支付回调处理失败，不返回通联，通联会主动重发");
        }
    }

    /**
     * 新回调处理
     *
     * @param request    请求报文
     * @param payType    支付渠道
     * @param merchantNo 商户号
     * @param response   响应
     */
    @RequestMapping(value = "/pay/notify/{payType}/{merchantNo}", method = RequestMethod.POST)
    public void appNewPayNotify(HttpServletRequest request, @PathVariable String payType, @PathVariable String merchantNo, HttpServletResponse response) {
        //动态遍历获取所有收到的参数,此步非常关键,因为收银宝以后可能会加字段,动态获取可以兼容
        TreeMap<String, String> params = getParams(request);
        LogUtil.info(logger, "收到通联支付回调通知new，参数：{0}", params);
        try {
            //通知传输的编码为GBK
            request.setCharacterEncoding("gbk");
            response.setCharacterEncoding("gbk");
            // 接受到推送通知,首先验签
            ChannelMerchantInfoEntity entity = apolloMerchantUtil.selectByPayChannelAndMerchantNoAndBizCode(payType, merchantNo, BusinessCodeEnum.WANLIMU.getBizCode());
            String appKey = null == entity ? tlConfig.getAppKey() : entity.getApiKey();
            boolean isSign = SybUtil.validSign(params, appKey);
            if (!isSign) {
                throw new SystemException(ExceptionEnum.TL1004);
            }
            //验签通过进行业务处理
            //bizCode用于从库里查询时的参数,线上已有业务全为万里目,且会调到这个回调方法的都是已有数据,故这里全部配置为wanlimu_code
            tongLianNotifyProcess.tongLianNotify(params, BusinessCodeEnum.WANLIMU.getBizCode(), tlConfig.getDingKey(), 0);
            //返回处理成功
            response.getOutputStream().write("success".getBytes());
            response.flushBuffer();
        } catch (Exception e) {
            LogUtil.error(logger, e, "通联支付回调处理失败，不返回通联，通联会主动重发");
        }
    }

    /**
     * 平台化通联回调处理
     *
     * @param request    请求报文
     * @param payType    支付渠道
     * @param merchantNo 商户号
     * @param bizCode    业务号
     * @param response   响应
     */
    @RequestMapping(value = "/pay/notify/{payType}/{bizCode}/{merchantNo}", method = RequestMethod.POST)
    public void appNewPayNotify(HttpServletRequest request, @PathVariable String payType, @PathVariable String bizCode, @PathVariable String merchantNo, HttpServletResponse response) {
        //动态遍历获取所有收到的参数,此步非常关键,因为收银宝以后可能会加字段,动态获取可以兼容
        TreeMap<String, String> params = getParams(request);
        LogUtil.info(logger, "收到通联支付回调通知plat new，参数：{0}", params);
        try {
            //通知传输的编码为GBK
            request.setCharacterEncoding("gbk");
            response.setCharacterEncoding("gbk");
            // 接受到推送通知,首先验签
            ChannelMerchantInfoEntity entity = apolloMerchantUtil.selectByPayChannelAndMerchantNoAndBizCode(payType, merchantNo, bizCode);
            String appKey = null == entity ? tlConfig.getAppKey() : entity.getApiKey();
            boolean isSign = SybUtil.validSign(params, appKey);
            if (!isSign) {
                throw new SystemException(ExceptionEnum.TL1004);
            }
            //验签通过进行业务处理
            tongLianNotifyProcess.tongLianNotify(params, bizCode, tlConfig.getDingKey(), 1);
            //返回处理成功
            response.getOutputStream().write("success".getBytes());
            response.flushBuffer();
        } catch (Exception e) {
            LogUtil.error(logger, e, "通联支付回调处理失败，不返回通联，通联会主动重发");
        }
    }


    /**
     * 动态遍历获取所有收到的参数,此步非常关键,因为收银宝以后可能会加字段,动态获取可以兼容由于收银宝加字段而引起的签名异常
     *
     * @param request
     * @return
     */
    private TreeMap<String, String> getParams(HttpServletRequest request) {
        TreeMap<String, String> map = new TreeMap<String, String>();
        Map reqMap = request.getParameterMap();
        for (Object key : reqMap.keySet()) {
            String value = ((String[]) reqMap.get(key))[0];
            map.put(key.toString(), value);
        }
        return map;
    }
}
